package com.fadada.api;

import com.fasc.open.api.bean.base.BaseRes;
import com.fasc.open.api.bean.base.BaseResponseEntity;
import com.fasc.open.api.bean.common.Field;
import com.fasc.open.api.bean.common.FieldPosition;
import com.fasc.open.api.bean.common.Notification;
import com.fasc.open.api.bean.common.OpenId;
import com.fasc.open.api.bean.req.signtask.*;
import com.fasc.open.api.bean.res.common.UrlRes;
import com.fasc.open.api.bean.res.signtask.*;
import com.fasc.open.api.client.SignTaskClient;
import com.fasc.open.api.enums.common.FieldTypeEnum;
import com.fasc.open.api.enums.common.IdTypeEnum;
import com.fasc.open.api.enums.common.NotifyWayEnum;
import com.fasc.open.api.enums.common.PositionModeEnum;
import com.fasc.open.api.enums.signtask.*;
import com.fasc.open.api.exception.ApiException;
import com.fasc.open.api.utils.ResultUtil;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author Fdd
 * @version 0.0.1
 * @ClassName SignTaskDemo.java
 * @Description
 * @Param
 * @createTime 2021/9/26 11:39
 */
public class SignTaskDemo extends BaseDemo {

    private static SignTaskClient signTaskClient;

    public static void main(String[] args) {
        try {
            BaseDemo baseDemo = new BaseDemo();
            openApiClient = baseDemo.getClient();
            signTaskClient = new SignTaskClient(openApiClient);
            //获取应用accessToken
            accessToken = baseDemo.getAccessToken(openApiClient);
            //创建签署任务
            createSignTask();
            //创建签署任务（基于签署模板）
            createWithTemplate();
            //添加签署任务文档
            addDocs();
            //移除签署任务文档
            deleteDocs();
            //添加签署任务控件
            addField();
            //移除签署任务控件
            deleteField();
            //获取签署任务控件设置链接
            getFieldUrl();
            //填写签署任务控件内容
            fillField();
            //添加签署任务附件
            addAttachs();
            //移除签署任务附件
            deleteAttachs();
            //添加签署任务参与方
            addActors();
            //移除签署任务参与方
            deleteActors();
            //发起签署任务
            initiate();
            //定稿签署任务文档
            finalizeDocs();
            //撤销签署任务
            cancel();
            //解阻签署任务
            unblock();
            //催办签署任务
            urge();
            //结束签署任务
            finish();
            //获取签署任务详情
            getDetail();
            //下载签署任务文档
            downloadFiles();
            //生成参与方用户的签署任务链接
            generateActorUserUrl();
        }catch (Exception e){
            e.printStackTrace();
        }
    }


    /**
     *
     * 创建签署任务
     *
     * **接口说明：**创建一个签署任务。该接口可创建一个简单的或要素完备的签署任务，因此可选参数较多，因此您可有下列选择：
     *
     * 1. 创建一个空白的签署任务，即暂不包含任何文档和参与方等核心要素，需要后续调用[添加签署任务文档](#添加签署任务文档)、[添加签署任务参与方](#添加签署任务参与方)等接口添加和完善签署任务要素，这是一种最简单的调用方式，但您的应用系统后续需要和法大大平台有多次调用交互；
     * 2. 创建包含文档、参与方等要素的更加完善的签署任务，这样可以减少调用接口次数，但需要一次性携带更多参数。
     *
     * **适用场景：** 无论是可以预先确定所有签署任务要素参数，还是文档、参与方等需要根据您的实际业务流程逐步确定的业务场景，都可以调用本接口创建一个签署任务。调用本接口后后续还可以调用其他接口调整其中的文档、附件和参与方等要素。
     *
     * **注意：**如果创建时未设置自动发起，需后续调用[发起签署任务](#发起签署任务)后，和其他参与方相关的协作流程才会开始流转。**如果在发起签署任务时，文档中有尚未填写的必填控件，或者有未填写的填写方，则将无法自动定稿文档。文档模板中带默认值的必填控件，在创建签署任务未指定填写方的情况下，在发起任务前需要调用[填写签署任务控件内容](#填写签署任务控件内容)接口进行确认填充动作，发起时则将自动定稿文档。**
     *
     * **授权要求：**应用系统需提前获得签署任务发起方的授权才可以将其设置为发起方。收到该接口调用后，法大大平台将检查授权信息和授权范围，如果该签署任务的initiator未授权，则将返回失败。因此您要在要求发起方的实名认证环节要求其授权或者单独要求其授权。参考[获取个人用户授权链接](#获取个人用户授权链接)、[获取企业用户授权链接](#获取企业用户授权链接)。
     *
     */
    public static void createSignTask() throws ApiException{
        CreateSignTaskReq createSignTaskReq = new CreateSignTaskReq();
        createSignTaskReq.setAccessToken(accessToken);
        //签署任务主题。长度最大100个字符。其他参与方在收到的通知和打开的页面上都可以醒目地看到该主题，并可作为各参与方管理和检索的关键标题，因此该参数非常重要，请认真编写。
        createSignTaskReq.setSignTaskSubject("签署任务主题");
        //该签署任务的发起方。特别注意授权要求：只有经过该发起方授权后，才可以将该发起方填写到此参数中并发起签署任务。
        createSignTaskReq.setInitiator(OpenId.getInstance(IdTypeEnum.CORP.getCode(), null,openCorpId));
        //任务过期时间。在此时间之后，该签署任务将自动终结。在自动终结时，如果所有签署方都签署完毕，则任务自动正常结束，否则任务将逾期作废。无此参数则不会过期。
        //格式为：[Unix标准时间戳](#时间标签取值说明)，精确到毫秒。该参数时间是未来时间，且和当前时间差不可小于10分钟(600000) 。
        createSignTaskReq.setExpiresTime("过期时间");
        //是否自动发起。false: 不自动发起 true: 自动发起 默认为false。
        //**注意：如果设置为true，则必须设置相关文档和参与方等必备要素。**
        createSignTaskReq.setAutoInitiate(false);
        //全部必填控件填写完成后是否自动定稿：false: 不自动定稿 true: 自动定稿 默认为true。
        //定稿之后就不允许任何参与方再填写或修改文档内容了，在填写流程结束后会自动将所填写内容合成到PDF文档中固化下来，并自动进入签署流程环节。
        createSignTaskReq.setAutoFillFinalize(true);
        //所有签署方签署完成后，签署任务是否自动结束：false: 不自动结束 true: 自动结束 默认为true。
        //结束后的签署任务将不可进行任何变动，并将生成签署完成的合同文件。
        createSignTaskReq.setAutoFinish(true);
        //填写流程是否有序：false: 无序 true: 有序 默认为false。
        createSignTaskReq.setFillInOrder(false);
        //签署流程是否有序：false: 无序 true: 有序 默认为false。
        createSignTaskReq.setSignInOrder(false);
        //您的业务应用系统中的业务场景信息，用于更好地定义业务场景和签署任务的关系。
        BusinessSceneInfo businessSceneInfo = new BusinessSceneInfo();
        //业务场景标识。长度最大32字节。指定该签署任务是某个特定业务场景的，参与各方可能对该业务场景有不同的控制逻辑和规则。
        //目前应用于“免验证签”服务上，应用系统的运营主体向法大大平台申请对特定业务场景开通“免验证签”服务，法大大审核通过后会生成一个businessId。法大大平台在处理带特定businessId的签署任务时，会针对不同的参与方判断是否授权使用“免验证签”进而确定该参与方的签署方式。
        businessSceneInfo.setBusinessId("业务场景标识");
        //业务参考号，由应用系统基于自身业务上下文提供。长度最大100个字符。该参数用于应用系统和签署任务建立关联关系，方便业务流程和数据的关联，例如可以是电商场景的订单号。
        businessSceneInfo.setTransReferenceId("业务参考号");
        createSignTaskReq.setBusinessScene(businessSceneInfo);
        //待签署的文档列表，文档数上限为20个。一个签署任务中可包含多份文档，请根据您的业务需要合理定义文档，
        //例如：建议将实际的业务中的”合同“定义到一个签署任务中当做文档。需要理解的是，携带的文档数量越多，将消耗更多的系统资源，并可能影响性能。在您和法大大的商务约定中，可能有限制一个签署任务中文档的数量上限，如遇问题，请咨询您组织中的商务人员。
        createSignTaskReq.setDocs(getDocs());
        //附件列表，附件数上限为20个。
        createSignTaskReq.setAttachs(getAttachs());
        //填写方列表。
        createSignTaskReq.setFillActors(getFillActors());
        //签署方列表。
        createSignTaskReq.setSignActors(getSignActors());
        //抄送方列表。
        createSignTaskReq.setCcActors(getCcActors());
        BaseRes<CreateSignTaskRes> res = signTaskClient.create(createSignTaskReq);
        ResultUtil.printLog(res, openApiClient.getJsonStrategy());
    }


    /**
     * 创建签署任务
     * 添加待签署的文档列表
     *
     */
    private static List<AddDocInfo> getDocs(){
        List<AddDocInfo> docs = new ArrayList<>();
        AddDocInfo docInfo = new AddDocInfo();
        //指定文档序号。
        //添加文档时定义，在同一个签署任务中不可重复。建议开发者根据期望向用户展示的顺序编排序号，例如：1、2、3、4、5。
        docInfo.setDocId(1);
        //指定在本签署任务中的文档名称。
        //添加文档时为其指定一个可被参与各方辨识的文档名称，长度最大256个字符。
        docInfo.setDocName("文件名称");
        //文档fileId。该参数和docTemplateId只能有一个，且必须有一个。
        docInfo.setDocFileId("文件id");
        //文档模板ID。
        docInfo.setDocTemplateId("文件模板id");
        //可在文档中添加一些控件。
        //注：当前仅支持添加签章控件。
        docInfo.setDocFields(fields());
        docs.add(docInfo);
        return docs;
    }

    /**
     * 创建签署任务
     * 添加附件列表，附件数上限为20个。
     *
     */
    private static List<AddAttachInfo> getAttachs(){
        List<AddAttachInfo> attachs = new ArrayList<>();
        AddAttachInfo attachInfo = new AddAttachInfo();
        //附件序号。
        //添加附件时定义，在同一个签署任务中不可重复。建议开发者根据期望向用户展示的顺序编排序号，例如：1、2、3。
        attachInfo.setAttachId(1);
        //附件名称。添加附件时为其指定一个可被参与各方辨识的附件名称，长度最大256个字符。
        attachInfo.setAttachName("附件名称");
        //附件fileId。
        attachInfo.setAttachFileId("附件id");
        attachs.add(attachInfo);
        return attachs;
    }


    /**
     * 创建签署任务 (基于签署模板)
     *
     * **接口说明：** 在预先已经创作好签署模板的情况下，直接基于签署模板创建比较完整的签署任务。这种方式更快捷方便。
     *
     * **适用场景：**一些固定的签署流程，可以预先定义更完整的签署模板，实现高度复用和提高效率。如果需求，调用本接口后，后续还可以调用其他接口调整其中的文档、控件、附件和参与方等要素。
     *
     * **注意：**如果创建时未设置自动发起，都需后续调用[发起签署任务](#发起签署任务)后，和其他参与方相关的协作流程才会开始流转。
     *
     * **授权要求：**应用系统需提前获得签署任务发起方的授权才可以将其设置为发起方。收到该接口调用后，法大大平台将检查授权信息和授权范围，如果该签署任务的initiator未授权，则将返回失败。因此您要在要求发起方的实名认证环节要求其授权或者单独要求其授权。参考[获取个人用户授权链接](#获取个人用户授权链接)、[获取企业用户授权链接](#获取企业用户授权链接)。
     *
     * **注意：**如果创建时未设置自动发起，需后续调用[发起签署任务](#发起签署任务)后，和其他参与方相关的协作流程才会开始流转。**如果在发起签署任务时，文档中有尚未填写的必填控件，或者有未填写的填写方，则将无法自动定稿文档。签署模板中带默认值的必填控件，在创建签署任务未指定填写方的情况下，在发起任务前需要调用[填写签署任务控件内容](#填写签署任务控件内容)接口进行确认填充动作，发起时则将自动定稿文档。**
     */
    public static void createWithTemplate()throws ApiException{
        CreateWithTemplateReq createWithTemplateReq = new CreateWithTemplateReq();
        createWithTemplateReq.setAccessToken(accessToken);
        //签署任务主题。长度最大100个字符。
        createWithTemplateReq.setSignTaskSubject("签署任务主题");
        //该签署任务的发起方。**特别注意授权要求：只有经过该发起方授权后，才可以将该发起方填写到此参数中并发起签署任务。**
        createWithTemplateReq.setInitiator(OpenId.getInstance(IdTypeEnum.CORP.getCode(),null,openCorpId));
        //任务过期时间。在此时间之后，该签署任务将自动终结。在自动终结时，如果所有签署方都签署完毕，则任务自动正常结束，否则任务将逾期作废。无此参数则不会过期。<br />格式为：[Unix标准时间戳](#时间标签取值说明)，精确到毫秒。该参数时间是未来时间，且和当前时间差不可小于10分钟(600000) 。
        createWithTemplateReq.setExpiresTime("过期时间");
        //签署任务是否自动发起协作流程：false: 不自动发起 true: 自动发起 默认为false。
        //注意：如果设置为true，则必须设置相关文档和参与方等必备要素。
        createWithTemplateReq.setAutoInitiate(false);
        //全部必填控件填写完成后是否自动定稿：false: 不自动定稿 true: 自动定稿 默认为true。
        //定稿之后就不允许任何参与方再填写或修改文档内容了，在填写流程结束后会自动将所填写内容合成到PDF文档中固化下来，并自动进入签署流程环节。
        //**注意：如果在发起签署任务时，文档中没有尚未填写的必填控件，则将自动定稿文档。**
        createWithTemplateReq.setAutoFillFinalize(true);
        //所有签署方签署完成后，签署任务是否自动结束：false: 不自动结束 true: 自动结束 默认为true。
        //结束后的签署任务将不可进行任何变动，并将生成签署完成的签名/签章文件(如合同)。
        createWithTemplateReq.setAutoFinish(true);
        //您的业务应用系统中的业务场景信息，用于更好地定义业务场景和签署任务的关系。
        BusinessSceneInfo businessSceneInfo = new BusinessSceneInfo();
        //业务场景标识。长度最大32字节。指定该签署任务是某个特定业务场景的，参与各方可能对该业务场景有不同的控制逻辑和规则。
        //目前应用于“免验证签”服务上，应用系统的运营主体向法大大平台申请对特定业务场景开通“免验证签”服务，法大大审核通过后会生成一个businessId。法大大平台在处理带特定businessId的签署任务时，会针对不同的参与方判断是否授权使用“免验证签”进而确定该参与方的签署方式。
        businessSceneInfo.setBusinessId("业务场景标识");
        //业务参考号，由应用系统基于自身业务上下文提供。长度最大100个字符。该参数用于应用系统和签署任务建立关联关系，方便业务流程和数据的关联，例如可以是电商场景的订单号。
        businessSceneInfo.setTransReferenceId("业务参考号");
        createWithTemplateReq.setBusinessScene(businessSceneInfo);
        //指定签署模板ID。 法大大平台将从该签署模板中复制预先设定的文档、控件和签署方，并对每个签署方指定具体的用户或企业。
        createWithTemplateReq.setSignTemplateId("签署模板ID");
        //填写方列表
        createWithTemplateReq.setFillActors(getTemplateFillActors());
        //签署方列表
        createWithTemplateReq.setSignActors(getTemplateSignActors());
        //抄送方列表
        createWithTemplateReq.setCcActors(getTemplateCcActors());
        BaseRes<CreateSignTaskRes> res = signTaskClient.createWithTemplate(createWithTemplateReq);
        ResultUtil.printLog(res, openApiClient.getJsonStrategy());
    }



    /**
     * 创建签署任务 (基于签署模板)
     * 获取填写方信息
     * @return
     * @throws ApiException
     */
    private static List<CreateWithTemplateFillActorInfo> getTemplateFillActors() throws ApiException{
        List<CreateWithTemplateFillActorInfo> fillActorList = new ArrayList<>();
        CreateWithTemplateFillActorInfo fillActor = new CreateWithTemplateFillActorInfo();
        //填写方信息，需要设置Actor.actorType=filler。
        fillActor.setFillActor(
                getActor(
                        ActorTypeEnum.FILLER.getCode(),"参与方标识：甲方",ActorIdentTypeEnum.CORP.getCode(),
                        getActorUser(""),
                        getActorCorp("",""),
                        Notification.getInstance(false,NotifyWayEnum.MOBILE.getCode(),"")
                ));
        //为填写控件设定默认值。大多数情况下，您的业务可能无需设置控件缺省值，则无需带此参数。因为在签署模板中，已经设定好参与方和控件的关系，因此这里的控件和参与方关系必须和模板中一致。
        fillActor.setActorFields(null);
        fillActorList.add(fillActor);
        return fillActorList;
    }


    /**
     * 创建签署任务 (基于签署模板)
     * 获取签署方列表
     * @return
     * @throws ApiException
     */
    private static List<CreateWithTemplateSignActorInfo> getTemplateSignActors() throws ApiException{
        List<CreateWithTemplateSignActorInfo> signActorList = new ArrayList<>();
        //签署方
        CreateWithTemplateSignActorInfo signActor = new CreateWithTemplateSignActorInfo();
        signActor.setSignActor(getActor(
                ActorTypeEnum.SIGNER.getCode(),"参与方标识：甲方",ActorIdentTypeEnum.CORP.getCode(),
                getActorUser(""),
                getActorCorp("",""),
                Notification.getInstance(false,NotifyWayEnum.MOBILE.getCode(),"")
        ));
        //当签署任务流转到此参与方时，是否暂时阻塞：false: 不阻塞 true: 阻塞 默认为false。
        //如果阻塞，暂不向该签署方发送通知和提醒，签署任务也暂停向下流转，直到调用接口[解阻签署任务](#解阻签署任务)接口将该签署任务解阻。
        signActor.setBlockHere(false);
        //是否请求该签署方免验证签：false: 否 ture: 是 //默认为false。
        //注：1. 如设置为true，当轮到签署方签署时，法大大平台将进一步判断其是否授权该签署场景免验证签权限：如有授权，法大大平台自动为其签署；如未授权，该签署方将依然需用正常方式签署。
        //2. 如此处设置为true，businessId必传。
        signActor.setRequestVerifyFree(false);
        //允许该参与方使用的身份和意愿确认方式：sms: 短信验证码 face: 刷脸验证 email: 邮件验证码
        //默认选择全部。
        String[] verifyMethods = {VerifyMethodEnum.SMS.getCode(),VerifyMethodEnum.EMAIL.getCode(),VerifyMethodEnum.FACE.getCode()};
        signActor.setVerifyMethods(Arrays.asList(verifyMethods));
        signActorList.add(signActor);
        return signActorList;
    }

    /**
     * 创建签署任务 (基于签署模板)
     * 获取抄送方
     * @return
     */
    private static List<SignTaskCcActorInfo> getTemplateCcActors() throws ApiException{
        List<SignTaskCcActorInfo> list = new ArrayList<>();
        SignTaskCcActorInfo ccActorInfo = new SignTaskCcActorInfo();
        ccActorInfo.setCcActor(getActor(
                ActorTypeEnum.CC.getCode(),"参与方标识：抄送",ActorIdentTypeEnum.CORP.getCode(),
                getActorUser(""),
                getActorCorp("",""),
                Notification.getInstance(false,NotifyWayEnum.MOBILE.getCode(),"")
                )
        );
        list.add(ccActorInfo);
        return list;
    }


    /**
     * 添加签署任务文档
     *
     * **接口说明：**对已经创建但尚未发起的签署任务添加文档。可以将已经上传的文档文件或预先定义好的文档模板作为签署任务文档添加进去。
     *
     * **适用场景：**本接口常常在[创建签署任务](#创建签署任务)之后使用，以添加和完善签署任务的文档，并且可以对这些文档设置控件。如果后续还需要对文档设置其他控件，则也可以通过[获取签署任务文档控件设置链接](#获取签署任务文档控件设置链接)接口获得页面，方便用户直接交互式对文档中的控件进行设置和修改。也可以通过[添加签署任务控件](#添加签署任务文档控件)接口添加控件。
     */
    public static void addDocs() throws ApiException{
        AddDocReq addDocReq =new AddDocReq();
        addDocReq.setAccessToken(accessToken);
        //签署任务ID
        addDocReq.setSignTaskId("签署任务id");
        //待签署的文档列表，可一次添加多份文档，一个签署任务中文档数上限为20个。一个签署任务中可包含多份文档，请根据您的业务需要合理定义文档，例如：建议将实际的业务中的”合同“定义到一个签署任务中当做文档。需要理解的是，携带的文档数量越多，将消耗更多的系统资源，并可能影响性能。在您和法大大的商务约定中，可能有限制一个签署任务中文档的数量上限，如遇问题，请咨询您组织中的商务人员。
        List<AddDocInfo> docs = new ArrayList<>();
        AddDocInfo docInfo = new AddDocInfo();
        //指定文档序号。
        //添加文档时定义，在同一个签署任务中不可重复。建议开发者根据期望向用户展示的顺序编排序号，例如：1、2、3、4、5。
        docInfo.setDocId(1);
        //指定在本签署任务中的文档名称。
        //添加文档时为其指定一个可被参与各方辨识的文档名称，长度最大256个字符。
        docInfo.setDocName("文件名称");
        //文档fileId。该参数和docTemplateId只能有一个，且必须有一个。
        docInfo.setDocFileId("文件id");
        //文档模板ID。
        docInfo.setDocTemplateId("文件模板id");
        //可在文档中添加一些控件。
        //注：当前仅支持添加签章控件。
        docInfo.setDocFields(fields());
        docs.add(docInfo);
        addDocReq.setDocs(docs);
        BaseRes<Void> res = signTaskClient.addDoc(addDocReq);
        ResultUtil.printLog(res, openApiClient.getJsonStrategy());
    }

    /**
     * 添加签署任务文档
     * 获取控件
     *
     */
    private static List<Field> fields(){
        List<Field> docFields = new ArrayList<>();
        //控件一 企业章
        Field field1 = new Field();
        field1.setFieldId("000001");
        field1.setFieldName("普通章控件");
        field1.setFieldType(FieldTypeEnum.CORP_SEAL.getCode());
        FieldPosition fieldPosition1 = new FieldPosition();
        fieldPosition1.setPositionMode(PositionModeEnum.PIXEL.getCode());
        field1.setPosition(fieldPosition1);

        //控件二 骑缝章
        Field field2 = new Field();
        field2.setFieldId("000002");
        field2.setFieldName("骑缝章控件");
        field2.setFieldType(FieldTypeEnum.CORP_SEAL_CROSS_PAGE.getCode());
        FieldPosition fieldPosition2 = new FieldPosition();
        fieldPosition2.setPositionMode(PositionModeEnum.PIXEL.getCode());
        field2.setPosition(fieldPosition2);

        docFields.add(field1);
        docFields.add(field2);
        return docFields;
    }

    /**
     * 移除签署任务文档
     * **接口说明：**从已经创建但尚未发起的签署任务删除文档。
     *
     * **适用场景：**用于删除不需要被签署的文档。
     * @throws ApiException
     */
    public static void deleteDocs() throws ApiException{
        DeleteDocReq deleteDocReq =new DeleteDocReq();
        deleteDocReq.setAccessToken(accessToken);
        //签署任务ID
        deleteDocReq.setSignTaskId("签署任务id");
        //文档序号docId列表。可一次性删除多个文档，如果列表中有的docId在该签署任务中已不存在，同样返回成功。
        List<Integer> docs = new ArrayList<>();
        deleteDocReq.setDocIds(docs);
        BaseRes<Void> res = signTaskClient.deleteDoc(deleteDocReq);
        ResultUtil.printLog(res, openApiClient.getJsonStrategy());
    }

    /**
     * 添加签署任务控件
     * **接口说明：**对已经创建但尚未发起的签署任务添加文档控件。
     *
     * **适用场景：**本接口用于希望微调增加文档控件的场景。
     * @throws ApiException
     */
    public static void addField() throws ApiException{
        AddFieldReq addFieldReq =new AddFieldReq();
        addFieldReq.setAccessToken(accessToken);
        //签署任务ID
        addFieldReq.setSignTaskId("签署任务id");
        //控件列表，可一次添加多个。
        List<AddFieldInfo> fields = new ArrayList<>();
        AddFieldInfo fieldInfo = new AddFieldInfo();
        //指定文档序号。
        fieldInfo.setDocId(1);
        //文档中的控件列表，注意同一个docId中的各个控件的fieldId不能重复。
        //建议您尽量采用模板定义控件，或通过[获取签署任务控件设置链接](#获取签署任务控件设置链接)接口获得页面链接进行人机交互式添加控件。
        fieldInfo.setDocFields(fields());

        fields.add(fieldInfo);
        addFieldReq.setFields(fields);
        BaseRes<Void> res = signTaskClient.addField(addFieldReq);
        ResultUtil.printLog(res, openApiClient.getJsonStrategy());
    }

    /**
     * 移除签署任务控件
     * **接口说明：**从已经创建但尚未发起的签署任务的文档中删除控件。。
     *
     * **适用场景：**本接口用于希望微调移除文档控件的场景。
     *
     */
    public static void deleteField() throws ApiException{
        DeleteFieldReq deleteFieldReq =new DeleteFieldReq();
        deleteFieldReq.setAccessToken(accessToken);
        //签署任务ID
        deleteFieldReq.setSignTaskId("签署任务id");
        //控件列表。
        List<DeleteFieldInfo> fields = new ArrayList<>();
        //控件
        DeleteFieldInfo fieldInfo = new DeleteFieldInfo();
        //指定文档序号。
        fieldInfo.setDocId(1);
        String[] fieldIds = {"控件编号1","控件编号2"};
        fieldInfo.setFieldIds(Arrays.asList(fieldIds));
        fields.add(fieldInfo);
        deleteFieldReq.setFields(fields);
        BaseRes<Void> res = signTaskClient.deleteField(deleteFieldReq);
        ResultUtil.printLog(res, openApiClient.getJsonStrategy());
    }

    /**
     * 获取签署任务控件设置链接
     *
     * **接口说明：**获取签署任务的填写控件、签章控件与参与方关系的设置链接。在权限控制上，该页面只允许签署任务的发起方成员操作。
     *
     * **适用场景：**签署任务中，存在填写控件、签章控件、参与方关系需要设置时，通过获取该页面链接供用户进行人机交互式设置。
     *
     * 例如：在指定位置签署的场景中，我们需要设置某个参与方的签署位置，就需要在发起前将该参与方和某个指定位置的签章控件关联。
     */
    public static void getFieldUrl() throws ApiException{
        GetFieldUrlReq getFieldUrlReq = new GetFieldUrlReq();
        getFieldUrlReq.setAccessToken(accessToken);
        //签署任务ID
        getFieldUrlReq.setSignTaskId("签署任务id");
        //该页面的实际操作人的openUserId。
        //该用户在访问页面内容时需完成帐号注册登录和授权。如果发起方主体是企业，则还需成为该企业的成员
        getFieldUrlReq.setOpenUserId("");
        //指定实际操作人的身份信息。
        getFieldUrlReq.setUserIdentInfo(null);
        //实际操作人补充信息。
        getFieldUrlReq.setUserInfoExtend(null);
        //重定向地址，控件设置操作完成后重定向跳转到该地址，并且附带上参数。
        getFieldUrlReq.setRedirectUrl("");
        BaseRes<UrlRes> res = signTaskClient.getFieldUrl(getFieldUrlReq);
        ResultUtil.printLog(res, openApiClient.getJsonStrategy());
    }


    /**
     * 填写签署任务控件内容
     *
     * **接口说明：**在签署任务发起之前，向一些填写控件中预先填写内容。
     *
     * **适用场景：**一些业务场景中，在签署任务发起之前，就已经确定了一些控件内容的时候，可以调用本接口进行填写。
     * 例如：在一个电商平台上，用户所下的订单中已经有确定了买卖双方、商品、价格和交付方式等参数，可以直接将这些参数的值一次性设置到控件中。
     *
     */
    public static void fillField() throws ApiException{
        FillFieldValuesReq fillFieldValuesReq = new FillFieldValuesReq();
        fillFieldValuesReq.setAccessToken(accessToken);
        fillFieldValuesReq.setSignTaskId("签署任务ID");
        //填写类控件列表
        fillFieldValuesReq.setDocFieldValues(getDocFieldValues());
        BaseRes<Void> res =signTaskClient.fillFieldValues(fillFieldValuesReq);
        ResultUtil.printLog(res, openApiClient.getJsonStrategy());
    }

    /**
     * 填写签署任务控件内容
     * 获取填写控件值
     */
    private static List<DocFieldValueInfo> getDocFieldValues(){
        List<DocFieldValueInfo> docFieldValues = new ArrayList<>();
        //控件
        DocFieldValueInfo field = new DocFieldValueInfo();
        //文档序号。
        field.setDocId(1);
        //控件ID。仅支持填写类控件。
        field.setFieldId("");
        field.setFieldValue("填充值");

        docFieldValues.add(field);
        return docFieldValues;
    }

    /**
     * 添加签署任务附件
     *
     * **接口说明：**对已经创建但尚未结束的签署任务添加附件。可以将已经上传的文件添加进去。
     *
     * **适用场景：**对签署任务添加附件，便于参与方参考。注意：任何形式的附件都不被签名。
     * @throws ApiException
     */
    public static void addAttachs() throws ApiException{
        AddAttachReq addAttachReq =new AddAttachReq();
        addAttachReq.setAccessToken(accessToken);
        //签署任务ID
        addAttachReq.setSignTaskId("签署任务id");
        //附件列表。
        List<AddAttachInfo> attachs = new ArrayList<>();
        AddAttachInfo attachInfo = new AddAttachInfo();
        //附件序号。
        //添加附件时定义，在同一个签署任务中不可重复。建议开发者根据期望向用户展示的顺序编排序号，例如：1、2、3。
        attachInfo.setAttachId(1);
        //附件名称。添加附件时为其指定一个可被参与各方辨识的附件名称，长度最大256个字符。
        attachInfo.setAttachName("附件名称");
        //附件fileId。
        attachInfo.setAttachFileId("附件id");
        attachs.add(attachInfo);
        addAttachReq.setAttachs(attachs);
        BaseRes<Void> res = signTaskClient.addAttach(addAttachReq);
        ResultUtil.printLog(res, openApiClient.getJsonStrategy());
    }

    /**
     * 移除签署任务附件
     *
     * **接口说明：**对已经创建但尚未结束的签署任务移除附件。
     *
     * **适用场景：**对签署任务移除附件。注意：因为附件不参与电子签名，因此删除附件不影响签署合同的有效性。
     * @throws ApiException
     */
    public static void deleteAttachs() throws ApiException{
        DeleteAttachReq deleteAttachReq =new DeleteAttachReq();
        deleteAttachReq.setAccessToken(accessToken);
        //签署任务ID
        deleteAttachReq.setSignTaskId("签署任务id");
        //附件序号attachId列表
        List<Integer> attachIds = new ArrayList<>();
        deleteAttachReq.setAttachIds(attachIds);
        BaseRes<Void> res = signTaskClient.deleteAttach(deleteAttachReq);
        ResultUtil.printLog(res, openApiClient.getJsonStrategy());
    }

    /**
     * 添加签署任务参与方
     * **接口说明：**对已经创建但尚未完成的签署任务添加参与方(包括填写方、签署方、抄送方)。
     *
     * - 签署任务**定稿后**，不再允许添加填写方；
     * - 签署任务**结束后**，不再允许添加签署方和抄送方；
     *
     * **适用场景：**本接口常常在[创建签署任务](#创建签署任务)之后使用，以添加和完善签署任务的参与方要素，并且可指定参与方应该对应的文档控件。
     * @throws ApiException
     */
    public static void addActors()throws ApiException{
        AddActorsReq addActorsReq = new AddActorsReq();
        addActorsReq.setAccessToken(accessToken);
        //签署任务id，通过创建签署任务接口返回
        addActorsReq.setSignTaskId("签署任务id");
        //填写方列表
        addActorsReq.setFillActors(getFillActors());
        //签署方列表。
        addActorsReq.setSignActors(getSignActors());
        //抄送方列表
        addActorsReq.setCcActors(getCcActors());
        BaseRes<Void> res = signTaskClient.addActor(addActorsReq);
        ResultUtil.printLog(res, openApiClient.getJsonStrategy());
    }

    /**
     * 添加签署任务参与方
     * 获取填写方列表
     * @return
     * @throws ApiException
     */
    private static List<AddFillActorInfo> getFillActors() throws ApiException{
        List<AddFillActorInfo> fillActorList = new ArrayList<>();
        //填写方 甲方企业
        AddFillActorInfo fillActor = new AddFillActorInfo();
        fillActor.setFillActor(getActor(
                ActorTypeEnum.FILLER.getCode(),"甲方企业",ActorIdentTypeEnum.CORP.getCode(),
                null,
                getActorCorp(openCorpId,null),
                Notification.getInstance(false,NotifyWayEnum.MOBILE.getCode(),"")
                )
        );
        //参与序号。如果签署任务要求有序填写，这里必须设定，按从小到大顺序排列。
        fillActor.setOrderNo(1);
        //该填写方关联的填写控件列表，建立参与方和控件关系。 如此处未指定该参数，后续也可在签署任务定稿前，通过[获取签署任务控件设置链接](#获取签署任务控件设置链接)接口获得页面链接，进行人机交互式设置(推荐使用这种方式)。
        fillActor.setActorFields(fillToField());
        fillActorList.add(fillActor);
        return fillActorList;
    }

    private static List<AddFillActorFieldInfo> fillToField(){
        List<AddFillActorFieldInfo> fieldList = new ArrayList<>();
        AddFillActorFieldInfo field1 = new AddFillActorFieldInfo();
        field1.setFieldDocId(1);
        field1.setFieldId("0000001");
        field1.setFieldValue("姓名xxx");
        AddFillActorFieldInfo field2 = new AddFillActorFieldInfo();
        field2.setFieldDocId(1);
        field2.setFieldId("0000002");
        field2.setFieldValue("身份证45243517829102");

        fieldList.add(field1);
        fieldList.add(field2);
        return fieldList;
    }

    /**
     * 添加签署任务参与方
     * 获取签署方列表
     * @return
     * @throws ApiException
     */
    private static List<AddSignActorInfo> getSignActors() throws ApiException{
        List<AddSignActorInfo> signActorList = new ArrayList<>();
        //签署方
        AddSignActorInfo signActor1 = new AddSignActorInfo();
        signActor1.setSignActor(getActor(
                ActorTypeEnum.SIGNER.getCode(),"甲方企业",ActorIdentTypeEnum.CORP.getCode(),
                getActorUser(openUserId),
                getActorCorp(openCorpId,openUserId),
                Notification.getInstance(false,NotifyWayEnum.MOBILE.getCode(),"")
        ));
        signActor1.setOrderNo(1);
        signActor1.setBlockHere(false);
        signActor1.setRequestVerifyFree(true);
        //设置签署控件
        List<AddSignActorFieldInfo> actorFields = new ArrayList<>();
        AddSignActorFieldInfo signActorField = new AddSignActorFieldInfo();
        signActorField.setFieldId("控件编号");
        signActorField.setFieldDocId(1);
        actorFields.add(signActorField);
        signActor1.setActorFields(actorFields);
        signActorList.add(signActor1);
        return signActorList;
    }

    /**
     * 添加签署任务参与方
     * 获取抄送方列表
     */
    private static List<SignTaskCcActorInfo> getCcActors()throws ApiException{
        List<SignTaskCcActorInfo> ccActorList = new ArrayList<>();
        SignTaskCcActorInfo ccActorInfo = new SignTaskCcActorInfo();
        ccActorInfo.setCcActor(getActor(
                ActorTypeEnum.CC.getCode(),"抄送方",ActorIdentTypeEnum.CORP.getCode(),
                getActorUser(openUserId),
                getActorCorp(openCorpId,openUserId),
                Notification.getInstance(false,NotifyWayEnum.MOBILE.getCode(),"")
        ));
        ccActorList.add(ccActorInfo);
        return ccActorList;
    }


    /**
     * 移除参与方
     * 该接口主要用于：
     *
     * 签署任务创建后需临时更换参与方的场景（移除原参与方，添加新参与方）；
     * 签署任务创建后，需临时取消某参与方填写或签署的场景；
     * @throws Exception
     */
    public static void deleteActors()throws Exception{
        DeleteActorReq deleteActorReq = new DeleteActorReq();
        deleteActorReq.setAccessToken(accessToken);
        //签署任务id，通过创建签署任务接口返回
        deleteActorReq.setSignTaskId("签署任务id");
        //参与方类型： 1: 填写方 2: 签署方 3: 抄送方。
        deleteActorReq.setActorType(ActorTypeEnum.SIGNER.getCode());
        //参与方在签署任务中被设定的唯一标识
        List<String> actorIds = new ArrayList<>();
        deleteActorReq.setActorIds(actorIds);
        BaseRes<Void> res = signTaskClient.deleteActor(deleteActorReq);
        ResultUtil.printLog(res, openApiClient.getJsonStrategy());
    }

    /**
     * 发起签署任务
     *
     * **接口说明：**对已经创建好且尚未发起的签署任务，下发发起协作流程指令，签署任务将按照预先设定的流程流转。
     *
     * **适用场景：**先创建好签署任务，填写完签署任务要素，发起流程。
     * @throws ApiException
     */
    public static void initiate()throws ApiException{
        SignTaskBaseReq signTaskBaseReq = new SignTaskBaseReq();
        signTaskBaseReq.setAccessToken(accessToken);
        //签署任务id
        signTaskBaseReq.setSignTaskId("签署任务id");
        BaseRes<Void> res = signTaskClient.initiate(signTaskBaseReq);
        ResultUtil.printLog(res, openApiClient.getJsonStrategy());
    }

    /**
     * 定稿签署任务文档
     *
     * **接口说明：**签署任务的所有必填控件填写完成后，调用本接口定稿，定稿完成后的文档将不可再被做任何填写修改。
     *
     * **适用场景：**如果创建时设定签署任务不自动定稿，则需要调用本接口进行定稿。
     * @throws ApiException
     */
    public static void finalizeDocs()throws ApiException{
        SignTaskBaseReq signTaskBaseReq = new SignTaskBaseReq();
        signTaskBaseReq.setAccessToken(accessToken);
        //签署任务id
        signTaskBaseReq.setSignTaskId("签署任务id");
        BaseRes<Void> res = signTaskClient.finalizeDoc(signTaskBaseReq);
        ResultUtil.printLog(res, openApiClient.getJsonStrategy());
    }


    /**
     * 撤销签署任务
     *
     * **接口说明：**撤销尚未结束的签署任务。
     *
     * **适用场景：**签署任务结束前，需要终止签署任务流程的情况下调用本接口。
     * @throws ApiException
     */
    public static void cancel()throws ApiException{
        SignTaskBaseReq signTaskBaseReq = new SignTaskBaseReq();
        signTaskBaseReq.setAccessToken(accessToken);
        //签署任务id，通过创建签署任务接口返回
        signTaskBaseReq.setSignTaskId("签署任务id");
        BaseRes<Void> res = signTaskClient.cancel(signTaskBaseReq);
        ResultUtil.printLog(res, openApiClient.getJsonStrategy());
    }


    /**
     * 解阻签署任务
     *
     * **接口说明：**解除签署任务某个参与方节点的阻塞设置。如果该签署任务正巧被阻塞在指定的参与方节点，则签署任务继续向下流转。
     *
     * **适用场景：**当需要接触签署任务某个参与方节点的阻塞设置时。
     * @throws ApiException
     */
    public static void unblock()throws ApiException{
        UnblockReq unblockReq = new UnblockReq();
        unblockReq.setAccessToken(accessToken);
        //签署任务id，通过创建签署任务接口返回
        unblockReq.setSignTaskId("签署任务id");
        //指定的参与方类型： 1: 填写方 2: 签署方 3: 抄送方 目前暂时是只有签署方会被阻塞。
        unblockReq.setActorType(ActorTypeEnum.SIGNER.getCode());
        //指定的参与方在本签署任务中的标识
        unblockReq.setActorId("");
        BaseRes<Void> res = signTaskClient.unblock(unblockReq);
        ResultUtil.printLog(res, openApiClient.getJsonStrategy());
    }

    /**
     * 催办签署任务
     * 对签署任务的当前处理人，进行短信催办
     * @throws Exception
     */
    public static void urge()throws Exception{
        SignTaskBaseReq signTaskBaseReq = new SignTaskBaseReq();
        signTaskBaseReq.setAccessToken(accessToken);
        //签署任务id
        signTaskBaseReq.setSignTaskId("签署任务id");
        BaseRes<Void> res = signTaskClient.urge(signTaskBaseReq);
        ResultUtil.printLog(res, openApiClient.getJsonStrategy());
    }

    /**
     * 结束签署任务
     *
     * **接口说明：**若创建签署任务时设定不自动结束，则在所有签署方都完成签署后，需要调动本接口驱动签署任务结束。签署任务结束后，会形成签署完结的合同，且不可再对该签署任务做任何动作。
     *
     * **适用场景：**创建签署任务时设定不自动结束，则在所有签署方都完成签署后，需要调动本接口驱动签署任务结束。
     * @throws Exception
     */
    public static void finish()throws Exception{
        SignTaskBaseReq signTaskBaseReq = new SignTaskBaseReq();
        signTaskBaseReq.setAccessToken(accessToken);
        //签署任务id
        signTaskBaseReq.setSignTaskId("签署任务id");
        BaseRes<Void> res = signTaskClient.finish(signTaskBaseReq);
        ResultUtil.printLog(res, openApiClient.getJsonStrategy());
    }




    /**
     * 获取签署任务详情
     *
     * **接口说明：**获取指定签署任务的详情信息和状态。
     *
     * **适用场景：**应用系统基于管理需求或希望查看签署任务当前进度、详情内容时调用。
     * @throws Exception
     */
    public static void getDetail()throws Exception{
        SignTaskBaseReq signTaskBaseReq = new SignTaskBaseReq();
        signTaskBaseReq.setAccessToken(accessToken);
        //签署任务id，通过创建签署任务接口返回
        signTaskBaseReq.setSignTaskId("签署任务id");
        BaseRes<SignTaskDetailRes> res = signTaskClient.getDetail(signTaskBaseReq);
        ResultUtil.printLog(res, openApiClient.getJsonStrategy());
    }


    /**
     * 下载签署任务文档
     *
     * **接口说明：**直接以文件形式下载签署任务中的文档或附件。如果不指定fileNo，则下载签署任务下的所有文档或附件(以压缩包文件格式)。如果不指定fileType和fileNo，则下载该签署任务下的所有文档和附件(以压缩包文件格式)。
     *
     * **适用场景：**应用系统如有对签署完成的文档进行备份管理述求，可以调用本接口直接下载文件。
     * @throws Exception
     */
    public static void downloadFiles()throws ApiException{
        DownloadFilesReq downloadDocsReq = new DownloadFilesReq();
        downloadDocsReq.setAccessToken(accessToken);
        //签署任务id，通过创建签署任务接口返回
        downloadDocsReq.setSignTaskId("签署任务id");
        //下载文件的类型：1. 文档file 2. 附件file 如此处不传参，不限制文件类型。
        downloadDocsReq.setFileType(FileTypeEnum.DOC.getCode());
        //指定签署任务中的docId或attachId
        downloadDocsReq.setId(1);
        BaseRes<BaseResponseEntity> res = signTaskClient.downloadFiles(downloadDocsReq);
        ResultUtil.printLog(res, openApiClient.getJsonStrategy());
    }



    /**
     * 生成参与方用户的签署任务链接
     *
     * **接口说明：**
     *
     * 生成签署任务针对特定参与方用户的访问链接。
     *
     * 1.业务发起方经办人：可访问页面进行查看签署任务详情。
     *
     * 2.未收到签署任务的参与方：无法进行填写或签署。
     *
     * 3.已收到签署任务的参与方：可进行填写或签署。
     *
     * **适用场景：**如希望参与方在应用系统中完成填写或签署，可调用该接口获取链接，把页面内嵌到应用系统中。
     * @throws ApiException
     */
    public static void generateActorUserUrl() throws ApiException{
        GetUrlReq getUrlReq = new GetUrlReq();
        getUrlReq.setAccessToken(accessToken);
        //签署任务ID。
        getUrlReq.setSignTaskId("签署任务id");
        //参与方类型：initiator: 发起方 filler: 填写方 signer: 签署方 cc: 抄送方
        getUrlReq.setActorType(ActorTypeEnum.SIGNER.getCode());
        //参与方在签署任务中被设定的唯一标识。只有actorType=initiator时该参数才是可忽略的，否则该参数是必填参数。
        getUrlReq.setActorId("");
        //重定向地址，参与动作完成之后重定向跳转到该地址。 若为空，则默认跳转到法大大结果页。
        getUrlReq.setRedirectUrl("");
        BaseRes<UrlRes> res = signTaskClient.getUrl(getUrlReq);
        ResultUtil.printLog(res, openApiClient.getJsonStrategy());

    }








}
